package com.neusoft.hifly.push.email.utils;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;

import org.apache.commons.lang3.StringUtils;

import com.neusoft.hifly.commons.exception.SystemErrorException;
import com.neusoft.hifly.commons.file.FileUtil;
import com.neusoft.hifly.core.log.Log;
import com.neusoft.hifly.push.email.auth.MyAuthenticator;
import com.neusoft.hifly.push.email.pojo.MailSenderInfo;

/**
 * Title: 核心类库
 * <p>
 * Description: 邮件发送器
 * <p>
 * Copyright: 2019
 * <p>
 * Company: 东软汉枫
 *
 * @author lh_neu
 * @version 1.0.0
 */
public class MailSender implements Runnable {

	/**
	 * 分号 ;
	 */
	public static final String STRING_SPLIT_FLAG_6 = ";";

	MailSenderInfo mailInfo;

	/**
	 * 构造方法
	 */
	public MailSender() {
	}

	/**
	 * 构造方法
	 *
	 * @param mailInfo
	 *            邮件实体
	 */
	public MailSender(final MailSenderInfo mailInfo) {
		this.mailInfo = mailInfo;
	}

	/**
	 * 执行线程
	 */
	@Override
	public void run() {
		if (mailInfo == null) {
			return;
		}
		try {
			sendMail(mailInfo);
		} catch (final SystemErrorException e) {
			Log.error(e.getErrorDesc());
		}
	}

	/**
	 * 以HTML格式发送邮件
	 *
	 * @param mailInfo
	 *            待发送的邮件信息
	 * @exception SystemErrorException
	 *                自定义异常
	 */
	public boolean sendMail(final MailSenderInfo mailInfo) throws SystemErrorException {
		if (mailInfo == null) {
			return false;
		}

		final Properties pro = mailInfo.getProperties();

		// 根据邮件会话属性和密码验证器构造一个发送邮件的session
		Session sendMailSession = null;
		// 判断是否需要身份认证
		if (mailInfo.isValidate()) {
			//如果需要身份认证，则创建一个密码验证器
			//			sendMailSession = Session.getDefaultInstance(pro,
			//					new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()));

			sendMailSession = Session.getInstance(pro,
					new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword()));

		} else {
			sendMailSession = Session.getDefaultInstance(pro);
		}

		if (mailInfo.isDebug()) {
			sendMailSession.setDebug(true);
		}
		try {
			// 根据session创建一个邮件消息
			final Message mailMessage = new MimeMessage(sendMailSession);
			// 创建邮件发送者地址
			final Address from = new InternetAddress(mailInfo.getFromAddress());
			// 设置邮件消息的发送者
			mailMessage.setFrom(from);
			// 创建邮件的接收者地址
			mailMessage.setRecipients(Message.RecipientType.TO, getToAddress(mailInfo.getToAddress()));
			// 创建邮件的抄送者地址
			mailMessage.setRecipients(Message.RecipientType.CC, getCcAddress(mailInfo.getCcAddress()));
			// 设置邮件消息的主题
			mailMessage.setSubject(mailInfo.getSubject());
			// 设置邮件消息发送的时间
			mailMessage.setSentDate(new Date());

			// MiniMultipart类是一个容器类，包含MimeBodyPart类型的对象
			// 添加附件，有附件和没附件的时候发送内容的方式是不一样的
			if ((mailInfo.getAttachs() != null) && !mailInfo.getAttachs().isEmpty()) {
				final Multipart mainPart = new MimeMultipart();

				// 设置邮件内容
				if (StringUtils.isNotEmpty(mailInfo.getContent())) {
					mainPart.addBodyPart(createContent(mailInfo.getContent()));
				}

				addAttach(mailInfo, mainPart);
				// 将MiniMultipart对象设置为邮件内容
				mailMessage.setContent(mainPart);
			} else {
				if (StringUtils.isNotEmpty(mailInfo.getContent())) {
					// 设置邮件消息的主要内容
					mailMessage.setDataHandler(new DataHandler(
							new ByteArrayDataSource(mailInfo.getContent(), "text/html; charset=UTF-8")));
				}
			}
			// 发送邮件
			Transport.send(mailMessage);
			return true;
		} catch (final Exception e) {
			if (e instanceof SystemErrorException) {
				final SystemErrorException e1 = (SystemErrorException) e;
				throw new SystemErrorException(e1.getErrorDesc());
			} else {
				throw new SystemErrorException(e.getMessage());
			}
		}
	}

	/**
	 * 邮件接收者的地址 (多个地址以(英文)分号分割)
	 *
	 * @param toAddress
	 *            接收者的地址
	 * @return 接收者的地址
	 * @throws SystemErrorException
	 *             系统异常
	 */
	private InternetAddress[] getToAddress(final String toAddress) throws SystemErrorException {
		if (StringUtils.isEmpty(toAddress)) {
			return null;
		}
		/**
		 * 收件地址:获取前台收件地址字符串
		 */
		// 根据;分割字符串
		final String[] toRecipientsAddressesArray = toAddress.split(MailSender.STRING_SPLIT_FLAG_6);
		// 创建内部地址类
		final InternetAddress[] internetAddresses = new InternetAddress[toRecipientsAddressesArray.length];
		/**
		 * 迭代实现创建内部地址类
		 */
		// 新增地址错误异常捕获，提供用户友好提醒
		StringBuffer sBuffer = new StringBuffer();
		for (int i = 0; i < internetAddresses.length; i++) {
			try {
				internetAddresses[i] = new InternetAddress(toRecipientsAddressesArray[i]);
			} catch (final Exception e) {
				sBuffer = i < internetAddresses.length - 1 ? sBuffer.append(toRecipientsAddressesArray[i] + ",")
						: sBuffer.append(toRecipientsAddressesArray[i]);
			}
		}
		if (sBuffer.length() > 0) {
			throw new SystemErrorException("收件人：" + sBuffer.toString() + "，地址格式错误");
		}
		return internetAddresses;
	}

	/**
	 * 邮件抄送者的地址 (多个地址以(英文)分号分割)
	 *
	 * @param ccAddress
	 *            抄送者的地址
	 * @return 抄送者的地址
	 * @throws SystemErrorException
	 *             系统异常
	 */
	private InternetAddress[] getCcAddress(final String ccAddress) throws SystemErrorException {
		if (StringUtils.isEmpty(ccAddress)) {
			return null;
		}
		final String[] ccRecipientsAddressesArray = ccAddress.split(MailSender.STRING_SPLIT_FLAG_6);
		final InternetAddress[] internetAddresses = new InternetAddress[ccRecipientsAddressesArray.length];
		// 新增地址错误异常捕获，提供用户友好提醒
		StringBuffer sBuffer = new StringBuffer();
		for (int i = 0; i < internetAddresses.length; i++) {
			try {
				internetAddresses[i] = new InternetAddress(ccRecipientsAddressesArray[i]);
			} catch (final Exception e) {
				sBuffer = i < internetAddresses.length - 1 ? sBuffer.append(ccRecipientsAddressesArray[i] + ",")
						: sBuffer.append(ccRecipientsAddressesArray[i]);
			}
		}
		if (sBuffer.length() > 0) {
			throw new SystemErrorException("抄送人：" + sBuffer.toString() + "，地址格式错误");
		}
		return internetAddresses;

	}

	/**
	 * 根据传入的邮件正文body和文件路径创建图文并茂的正文部分
	 *
	 * @param body
	 *            窗体
	 * @return text
	 * @throws Exception
	 *             异常
	 */
	private BodyPart createContent(final String body) throws Exception {
		// 创建一个包含HTML内容的MimeBodyPart
		final MimeBodyPart html = new MimeBodyPart();
		// 设置HTML内容
		html.setDataHandler(
				new DataHandler(new ByteArrayDataSource(mailInfo.getContent(), "text/html; charset=UTF-8")));
		return html;
	}

	/**
	 * @param mailInfo
	 *            待发送的邮件信息
	 * @param mainPart
	 *            容器
	 * @throws SystemErrorException
	 *             系统异常
	 */
	private void addAttach(final MailSenderInfo mailInfo, final Multipart mainPart) throws SystemErrorException {
		if ((mailInfo == null) || (mainPart == null)) {
			return;
		}
		final Map<String, String> attachs = mailInfo.getAttachs();
		if (attachs == null || attachs.isEmpty()) {
			return;
		}
		MimeBodyPart filePart;
		FileDataSource filedatasource;
		// 新增地址错误异常捕获，提供用户友好提醒
		StringBuffer sBuffer = new StringBuffer();
		// 逐个加入附件
		final Iterator<Map.Entry<String, String>> iter = attachs.entrySet().iterator();
		int i = 0;
		while (iter.hasNext()) {
			final Map.Entry<String, String> entry = iter.next();
			String key = entry.getKey(); // 附件名称，可不带扩展名
			final String val = entry.getValue(); // 附件物理路径

			// 判断附件是否存在
			if (!FileUtil.exists(val)) {
				sBuffer = i++ < attachs.size() - 1 ? sBuffer.append(key + ",") : sBuffer.append(key);
				continue;
			}
			try {
				filePart = new MimeBodyPart();
				filedatasource = new FileDataSource(val);
				filePart.setDataHandler(new DataHandler(filedatasource));

				// 判断是否带扩展名
				key = MimeUtility.encodeText(key);
				if (StringUtils.isNotEmpty(key) && (key.indexOf(".") == -1)) {
					key = key + FileUtil.getSuffix(val);
				}

				filePart.setFileName(key);

				mainPart.addBodyPart(filePart);
			} catch (final Exception e) {
				e.printStackTrace();
			}
		}

		if (sBuffer.length() > 0) {
			throw new SystemErrorException("附件：" + sBuffer.toString() + "，不存在");
		}
		/* 指定附件格式 */
		final MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
		mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
		mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
		mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
		mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
		mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
		CommandMap.setDefaultCommandMap(mc);
	}

}
